<?php
/**
 * This file is part of the symfony package.
 * Copyright (c) 2007 Dino Co.,Ltd.
 *
 * @package    symfony
 * @subpackage plugin
 * @author     Yoshihiro TAKAHARA <takahara@dino.co.jp
 * @version    SVN: $Id$
 *
 *
 *
 * ※全データを取得するメソッドが無かったので
 * getDataAll() を追加しています。
 */
class sfPageFlow
{
    protected $config = array();

    protected $module = null;

    public function __construct($config)
    {
        $this->config = $config;
    }
    public static function getInstance($action,$root,$flowId,$module = null){
        $obj = new self(self::loadPageFlowConfig($module));
        $obj->module = $module;
        $obj->flowId = $flowId;
        $state = $obj->getState();
        if(!$state){
            $obj->setState($obj->config["firstState"]);
            $obj->clearData();
        }
        $obj->action = $action;
        $obj->root = $root;

        return $obj;
    }
    public static function loadPageFlowConfig($module = null)
    {
        if(!$module){
            $module = sfContext::getInstance()->getModuleName();
        }

        $config = include
            (sfConfigCache::getInstance()->checkConfig
             (sprintf("modules/%s/config/pageflow.yml"
                      ,$module)));
        return $config;
    }
    public function getNamespace()
    {
        if (!$this->module) {
            $this->module = sfContext::getInstance()->getModuleName();
        }

        return $this->module.$this->flowId.".page-flow";
    }

    public function getState(){
        return sfContext::getInstance()->getUser()
            ->getAttribute("state",null,$this->getNamespace());
    }
    public function setState($state){
        sfContext::getInstance()->getUser()
            ->setAttribute("state",$state,$this->getNamespace());
    }
    public function getErrors(){
        return sfContext::getInstance()->getUser()
            ->getAttribute("errors",null,$this->getNamespace());
    }
    public function setErrors($errors){
        sfContext::getInstance()->getUser()
            ->setAttribute("errors",$errors,$this->getNamespace());
    }

    /**
     * transit by event
     */
    public function transit($event){
        $request = sfContext::getInstance()->getRequest();

        if(!$this->hasEvent($event)){
            $state = $this->getState();
            $this->reset();
            throw new sfException
                (sprintf("Unknown State '%s' of event '%s'",$state,$event));
        }

        foreach($this->getExitActions() as $fname => $params){
            $this->action->$fname($params["params"]);
        }

        $fromActionState = $this->isActionState();
        $this->setState($this->config["state"][$this->getState()]["transition"][$event]);

        $event = $this->getDoEvent();

        if($fromActionState){
            if($event){
                $this->setErrors($request->getErrors());
                return $this->action->redirect($this->root.'?flow_id='.$this->flowId);
            }
        }
        return $this->getState();
    }
    public function transitOn($event){
        return $this->transit("on".$event);
    }
    public function transitOnSuccess(){
        $this->setErrors(null);
        return $this->transitOn("Success");
    }
    public function transitOnError(){
        return $this->transitOn("Error");
    }


    public function acceptRequests($vars){
        $request = sfContext::getInstance()->getRequest();
        foreach($vars as $var){
            $this->setData($var,$request->getParameter($var));
        }
    }

    public function hasEvent($event){
        return isset($this->config["state"][$this->getState()]["transition"][$event]);
    }

    public function hasEntryAction(){
        return isset($this->config["state"][$this->getState()]["entry"]);

    }
    public function getEntryActions(){
        if($this->hasEntryAction()){
            return $this->config["state"][$this->getState()]["entry"];
        }
        return array();
    }
    public function hasExitAction(){
        return isset($this->config["state"][$this->getState()]["exit"]);

    }
    public function getExitActions(){
        if($this->hasExitAction()){
            return $this->config["state"][$this->getState()]["exit"];
        }
        return array();
    }

    public function isViewState(){
        return substr($this->getState(),0,7) == "Display";
    }
    public function isActionState(){
        return substr($this->getState(),0,7) == "Process";
    }
    public function reset(){
        sfContext::getInstance()->getUser()
            ->setAttribute("state",null,$this->getNamespace());
    }
    public function doEvent(){
        $event = $this->getDoEvent();

        if($this->hasEvent($event)){
            $this->transit($event);
        }
    }
    public function getDoEvent(){
        $event = sfContext::getInstance()->getRequest()->getParameter("pageflow_event",null);

        sfLogger::getInstance()->info($event);
        return $event;
    }
    public function processAction(){
        $module = $this->module ? $this->module : sfContext::getInstance()->getModuleName();

        foreach($this->getEntryActions() as $fname => $params){
            $this->action->$fname($params["params"]);
        }

        if( $this->isActionState() ){
            $action_name = sfInflector::underscore(substr($this->getState(),7));
        }else{
            if($errors = $this->getErrors()){
                sfContext::getInstance()->getRequest()->setErrors($errors);
            }

            $action_name = "display";
        }
        $this->action->getRequest()->setAttribute("flow_id", $this->flowId);
        $this->action->forward($module,$action_name);
    }

    public function display(){
        if($this->isViewState()){
            $view =  substr($this->getState(),7);
        }
        if($this->isLastState()){
            $this->reset();
        }
        return $view;

    }

    public function isLastState(){
        return ($this->config["lastState"] == $this->getState());
    }

    public function execute()
    {
        $this->processAction();
    }

    public function getData($var,$default = null){
        $ns = $this->getNamespace()."-data";
        return sfContext::getInstance()->getUser()->getAttribute($var,$default,$ns);
    }

    public function setData($var,$val){
        $ns = $this->getNamespace()."-data";
        sfContext::getInstance()->getUser()->setAttribute($var,$val,$ns);
    }

    public function clearData(){
        $ns = $this->getNamespace()."-data";
        sfContext::getInstance()->getUser()->getAttributeHolder()->removeNamespace($ns);
    }

    public function getDataAll()
    {
        $ns = $this->getNamespace()."-data";
        return sfContext::getInstance()->getUser()->getAttributeHolder()->getAll($ns);
    }
}
